package com.mm.cloud.sys.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mm.cloud.common.redis.constant.RedisKeySystemConstants;
import com.mm.cloud.common.redis.service.IRedisService;
import com.mm.cloud.common.redis.util.RedisKeyStringUtils;
import com.mm.cloud.common.core.constant.CommonConstants;
import com.mm.cloud.common.core.enums.DeleteEnum;
import com.mm.cloud.common.core.exception.BaseException;
import com.mm.cloud.common.core.result.Result;
import com.mm.cloud.common.core.result.ResultConstants;
import com.mm.cloud.common.core.result.ResultUtil;
import com.mm.cloud.common.security.annotation.ParameterCheck;
import com.mm.cloud.common.security.helper.LoginUserHelper;
import com.mm.cloud.common.security.loginuser.LoginUser;
import com.mm.cloud.feign.sys.api.dto.BtnPermissionCodeFeignDTO;
import com.mm.cloud.sys.dto.form.PermissionDTO;
import com.mm.cloud.sys.dto.query.QueryPermissionDTO;
import com.mm.cloud.sys.entity.Permission;
import com.mm.cloud.sys.mapper.PermissionMapper;
import com.mm.cloud.sys.service.IPermissionService;
import com.mm.cloud.sys.vo.MetaVO;
import com.mm.cloud.sys.vo.PermissionVO;
import com.mm.cloud.sys.vo.RouterVO;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 资源基础信息 服务实现类
 * </p>
 *
 * @author mr
 * @since 2020-09-15
 */
@Service
@AllArgsConstructor
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {

    private final IRedisService<String, Object> redisService;

    @Override
    public Result<List<PermissionVO>> getPermissionList(QueryPermissionDTO dto) {
        //查询所有菜单
        List<Permission> permissions = this.baseMapper.selectList(Wrappers.<Permission>lambdaQuery()
                .eq(Permission::getIsDelete, DeleteEnum.NOT_DELETE.getStatus()));
        return ResultUtil.success(initPermission(permissions));
    }

    /**
     * 初始化菜单
     *
     * @param permissions
     * @return
     */
    private List<PermissionVO> initPermission(List<Permission> permissions) {
        //按照父级ID分组
        Map<Long, List<Permission>> permissionMap = permissions.stream().collect(Collectors.groupingBy(Permission::getPid));
        //父级菜单
        List<Permission> parentList = permissionMap.get(0L);
        //构建菜单
        List<PermissionVO> list = new ArrayList<>();
        if (!CollectionUtils.isEmpty(parentList)) {
            for (Permission parent : parentList) {
                buildPermission(parent, permissionMap, list);
            }
            //排序
            Collections.sort(list);
        }
        return list;
    }

    /**
     * 构建菜单
     *
     * @param parent
     * @param permissionMap
     * @param list
     */
    private void buildPermission(Permission parent, Map<Long, List<Permission>> permissionMap, List<PermissionVO> list) {
        PermissionVO parentVO = new PermissionVO();
        BeanUtils.copyProperties(parent, parentVO);
        //构建子级菜单
        List<Permission> childrenList = permissionMap.get(parent.getId());
        if (!CollectionUtils.isEmpty(childrenList)) {
            List<PermissionVO> childrenListVO = new ArrayList<>();
            for (Permission children : childrenList) {
                buildPermission(children, permissionMap, childrenListVO);
            }
            childrenListVO.forEach(vo -> vo.setPtitle(parent.getTitle()));
            //排序
            Collections.sort(childrenListVO);
            parentVO.setChildren(childrenListVO);
        }
        list.add(parentVO);
    }

    @Override
    @ParameterCheck
    public Result<String> savePermission(PermissionDTO dto) {
        // 校验编码是否存
        if(StringUtils.isNotEmpty(dto.getPermissionCode())) {
            Permission existPermission = this.getOne(Wrappers.<Permission>lambdaQuery().eq(Permission::getPermissionCode, dto.getPermissionCode()).eq(Permission::getIsDelete, DeleteEnum.NOT_DELETE.getStatus()));
            if (Objects.nonNull(existPermission)) {
                return ResultUtil.fail("权限标识已存在");
            }
        }
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        Permission permission = new Permission();
        BeanUtils.copyProperties(dto, permission);
        permission.setCreaterId(loginUser.getUserId());
        permission.setCreateTime(LocalDateTime.now());
        permission.setIsDelete(DeleteEnum.NOT_DELETE.getStatus());
        this.save(permission);
        return ResultUtil.success();
    }

    @Override
    @ParameterCheck
    public Result<String> updatePermission(PermissionDTO dto) {
        Permission permission = getPermissionAssert(dto.getId());

        // 校验编码是否存
        if(StringUtils.isNotEmpty(dto.getPermissionCode())) {
            Permission existPermission = this.getOne(Wrappers.<Permission>lambdaQuery()
                    .eq(Permission::getPermissionCode, dto.getPermissionCode())
                    .eq(Permission::getIsDelete, DeleteEnum.NOT_DELETE.getStatus())
                    .ne(Permission::getId, permission.getId()));
            if (Objects.nonNull(existPermission)) {
                return ResultUtil.fail("权限标识已存在");
            }
        }

        LoginUser loginUser = LoginUserHelper.getLoginUser();
        BeanUtils.copyProperties(dto, permission);
        permission.setUpdaterId(loginUser.getUserId());
        permission.setUpdateTime(LocalDateTime.now());
        this.updateById(permission);
        return ResultUtil.success();
    }

    @Override
    @ParameterCheck
    public Result<String> deletePermission(@NotNull(message = "参数不能为空") Long permissionId) {
        Permission permission = getPermissionAssert(permissionId);
        permission.setUpdaterId(LoginUserHelper.getLoginUser().getUserId());
        permission.setUpdateTime(LocalDateTime.now());
        permission.setIsDelete(DeleteEnum.DELETE.getStatus());
        this.updateById(permission);
        return ResultUtil.success();
    }

    @Override
    public Result<List<RouterVO>> init(Byte platformType) {
        LoginUser loginUser = LoginUserHelper.getLoginUser();
        final String key = RedisKeyStringUtils.appendRedisKey(RedisKeySystemConstants.REDIS_INIT_PERMISSION, loginUser.getToken(), platformType);
        List<PermissionVO> list = null;
        List<JSONObject> cache = (List<JSONObject>) redisService.get(key);
        if (CollectionUtils.isEmpty(cache)) {
            List<Permission> permissions = null;
            if (loginUser.isAdmin()) {
                permissions = this.baseMapper.initAll(platformType);
            } else {
                permissions = this.baseMapper.initByUserId(loginUser.getUserId(), platformType);
            }
            if (CollectionUtils.isEmpty(permissions)) {
                return ResultUtil.success();
            }
            list = initPermission(permissions);
            redisService.set(key, list, RedisKeySystemConstants.RedisCacheTimeEnum.TOKEN.getTime(), RedisKeySystemConstants.RedisCacheTimeEnum.TOKEN.getUnit());
        } else {
            list = JSONObject.parseArray(cache.toString(), PermissionVO.class);
        }
        return ResultUtil.success(buildPermissions(list));
    }

    /**
     * 构建路由
     *
     * @param permissions
     * @return
     */
    public List<RouterVO> buildPermissions(List<PermissionVO> permissions) {
        List<RouterVO> routers = new LinkedList<>();
        for (PermissionVO permission : permissions) {
            RouterVO router = new RouterVO();
            router.setHidden(false);
            router.setName(permission.getName());
            router.setPath(permission.getPath());
            router.setComponent(permission.getComponent());
            router.setMeta(new MetaVO(permission.getTitle(), permission.getIcon(), true));
            List<PermissionVO> cMenus = permission.getChildren();
            if (!CollectionUtils.isEmpty(cMenus)) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildPermissions(cMenus));
            }
            routers.add(router);
        }
        return routers;
    }

    @Override
    @ParameterCheck
    public Result<List<String>> getBtnPermissionCode(BtnPermissionCodeFeignDTO dto) {
        if (this.isAdmin(dto.getRoles())) {
            return ResultUtil.success(this.baseMapper.getAllBtnPermission());
        }
        return ResultUtil.success(this.baseMapper.getBtnPermissionCodeByUserId(dto.getUserId()));
    }

    /**
     * 是否管理员
     *
     * @param roles
     * @return
     */
    private boolean isAdmin(Set<String> roles) {
        if (CollectionUtils.isEmpty(roles)) {
            return false;
        }
        return roles.contains(CommonConstants.ADMIN);
    }

    /**
     * 查询资源信息
     *
     * @param permissionId 资源ID
     * @return Permission
     */
    private Permission getPermissionAssert(Long permissionId) {
        Assert.notNull(permissionId, "permissionId is null");
        Permission permission = this.getOne(Wrappers.<Permission>lambdaQuery().eq(Permission::getId, permissionId).eq(Permission::getIsDelete, DeleteEnum.NOT_DELETE.getStatus()));
        if (Objects.isNull(permission)) {
            throw new BaseException(ResultConstants.QUERY_NOT_FOUND_DATA);
        }
        return permission;
    }

}
